const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`

const qnameCapture = `((?:${ncname}\\:)?${ncname})`

const startTagOpen = new RegExp(`^<${qnameCapture}`)  //匹配到开始标签 <div

const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`) //匹配到结束标签 </div>

const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/

const startTagClose = /^\s*(\/?)>/  // 匹配 > 或者 />

const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g

// 对模板进行编译处理
// vue3不是用正则

// 解析html 解析一个删除一个 解析完毕，删除完毕
export function parseHTML(html) { //最开始是一个 < 

  const ElEMENT_TYPE = 1
  const TEXT_TYPE = 3
  const stack = [] // 用于存放元素的栈
  let currentParent; // 指向栈中的最后一个
  let root;

  function createASTElemnt(tag, attrs) {
    return {
      tag,
      type: ElEMENT_TYPE,
      children: [],
      attrs: attrs || [],
      parent: null
    }
  }

  function start(tag, attrs) {
    let node = createASTElemnt(tag, attrs)
    if (!root) { // 是否为空树
      root = node  // 为空则当前节点是树根节点
    }
    if (currentParent) {
      node.parent = currentParent
      currentParent.children.push(node)
    }
    stack.push(node)
    currentParent = node //currentParent 为栈中的最后一个
  }

  function charts(text) { // 文本直接放到当前指向的节点
    text = text.replace(/\s/g, '')
    text && currentParent.children.push({
      type: TEXT_TYPE,
      text,
      parent: currentParent
    })
  }

  function end(tag) {
    stack.pop()
    currentParent = stack[stack.length - 1]
  }
  // 前进删除已匹配的html
  function advance(n) {
    html = html.substring(n)
  }


  function parseStartTag() {
    const start = html.match(startTagOpen)
    if (start) {
      const match = {
        tagName: start[1],
        attrs: []
      }

      advance(start[0].length)

      // 如果不是开始标签的结束 就一直匹配下去
      let attr, end
      while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
        advance(attr[0].length)
        match.attrs.push({ name: attr[1], value: attr[3] || attr[4] || attr[5] || true })
      }

      if (end) {
        advance(end[0].length)
      }
      return match
    }
    // 如果鄙视开始标签的结束，就一直匹配下去

    return false
  }

  while (html) {
    let textEnd = html.indexOf('<') // 如果索引是0则说明是个开始或者结束标签  如果textEnd>0说明是文 本结束位置
    if (textEnd === 0) {
      const startTagMatch = parseStartTag() // 开始标签的匹配结果
      const endTagMatch = html.match(endTag)

      // 处理解析到的开始标签
      if (startTagMatch) {
        start(startTagMatch.tagName, startTagMatch.attrs)
        continue
      }

      // 处理结束标签
      if (endTagMatch) {
        end(endTagMatch.tagName)
        advance(endTagMatch[0].length)
        continue
      }

    }
    if (textEnd > 0) {
      const text = html.substring(0, textEnd)
      if (text) {
        advance(text.length)
        charts(text)
      }

    }
  }
  return root
}